-- GiftM
-- created by panyl
-- 礼包

module("GiftM", package.seeall);

local gifts = {};

-- 子规则
local rules = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    local gift_CSV = get_gift_CSV();
    for i = 1, #gift_CSV do
        local row = gift_CSV[i];

        gifts[row.classify] = gifts[row.classify] or {};

        gifts[row.classify][row.grade] = row;
    end
end

-- 模块初始化操作
function init()
    if not _init then
        loadCsv();

        -- 载入所有的规则处理子模块
        rules = LOAD_PATH("game/logic/module/gift");
    end    

    EventMgr.removeAll("GiftM");
    EventMgr.register("GiftM", event.BUY_GOODS, function(para)
        local goodsId = para.goodsId;
        whenBuyGoods(goodsId);
    end);
end

-- 购买商品回调
function whenBuyGoods(goodsId)
    -- 检查是否达成限时礼包要求
    local limitGiftInfo = table.deepcopy(ME.user.dbase:query("limit_time_gift") or {});
    local giftInfo = limitGiftInfo["gift_info"];
    if giftInfo and limitGiftInfo["achieve"] ~= 1 then
        local requireGoodId = giftInfo["good_id"];
        if requireGoodId == goodsId then
            -- 完成了
            limitGiftInfo["achieve"] = 1;
            ME.user.dbase:set("limit_time_gift", limitGiftInfo);
            -- 抛出完成事件
            EventMgr.fire(event.ACHIEVE_TIME_GIFT, {});
        end
    end
end

function query(class, grade)
    local m = gifts[class];

    if not m or not grade then
        return m;
    end

    return m[grade];
end

-- 奖励
function calcBonus(class, grade)
    local config = query(class, grade)

    if type(config["bonus"]) == "table" then
        return config["bonus"];
    end

    local formula;
    if type(config["bonus"]) == "string" and
        string.startWith(config["bonus"], "formula_") then
        formula = string.sub(config["bonus"], string.len("formula_") + 1);
        local args = table.deepcopy(config["bonus_arg"]);
        return FormulaM.invoke(formula, args, config["backup_arg"]);
    end
end

-- 获取当前进度
function getProgress(class)
    local mod = rules[class];
    if not mod then
        return;
    end

    -- 子模块获取
    return mod.getProgress();
end

-- 检查进度
function checkProgress(class, grade)
    if not query(class, grade) then
        return false;
    end

    local mod = rules[class];
    if not mod then
        return false;
    end

    -- 子模块判断
    return mod.checkProgress(grade);
end

-- 某档位是否已经领取过
function beAlreadyTook(class, grade)
    local mod = rules[class];
    if not mod then
        return false;
    end

    -- 子模块判断
    if mod.hasTook then
        return mod.hasTook(grade);
    end

    -- 通用的判断流程
    local received = ME.user.dbase:query("received_gift", {});
    local record = received[class] or 0;

    if record >= grade then
        -- 已经领取过了
        return true;
    end

    return false;
end

-- 判断能否领取礼包
function canTakeGift(class, grade)
    if beAlreadyTook(class, grade) then
        -- 已经领取过了
        return false;
    end

    return checkProgress(class, grade);
end

-- 标记领取
function recordTook(class, grade)
    local mod = rules[class];
    if not mod then
        return false;
    end

    -- 子模块判断
    if mod.recordTook then
        return mod.recordTook(grade);
    end

    -- 通用流程
    local received = ME.user.dbase:query("received_gift", {});
    local record = received[class] or 0;

    -- 标记
    received[class] = grade;
    ME.user.dbase:set("received_gift", received);
end

-- 领取奖励
function takeGift(class, grade)
    if not canTakeGift(class, grade) then
        return false;
    end

    recordTook(class, grade);

    -- 奖励
    local arr = calcBonus(class, grade);
    for _, bonus in pairs(arr) do
        BonusM.doBonus(bonus, "gift");
    end

    -- 通知服务器
    SyncM.addMessage("CMD_TAKE_GIFT", {["class"] = class, ["grade"] = grade,});
    SyncM.startSync();

    -- 抛出领取奖励事件
    EventMgr.fire(event.TAKE_GIFTS_BONUS, { ["bonusList"] = arr, });
    return true;
end

-- 已领取的奖励个数
function getHasGetGiftNum(class)
    local num = 0;
    if class == "boss" then
        local showNum = GiftM.getCurUnlockBossGift();
        local totalNum = 0;
        for grade = 1, showNum do
            if beAlreadyTook("boss", grade) then
                totalNum = totalNum + 1;
            end
        end
        num = totalNum;
    else
        local giftInfo = ME.user.dbase:query("received_gift", {});
        local recieveNum = giftInfo[class];
        num = recieveNum and recieveNum or 0;
    end
    
    return num;
end

-- 可领取奖励的个数
function getCanTakeGiftNum(class)
    local num = 0 ;
    local allGradeList = query(class);
    for k, value in pairs(allGradeList) do
        if canTakeGift(class, value.grade) then
            -- 计算奖励的个数
            num = num + 1;
        end
    end

    return num;
end

-- 当前剩余礼包数量
function getLeftGift(class)
    local num = 0 ;
    local allGradeList = query(class);

    for k, value in pairs(allGradeList) do
        if  not beAlreadyTook(class, value.grade) then
            -- 计算奖励的个数
            num = num + 1;
        end
    end

    return num;
end

-- 当前已解锁的BOSS礼包数量
function getCurUnlockBossGift()
    local list = GiftM.getKillBossGift();
    local num = #list ~= 0 and #list or 0;
    return num;
end

-- 计算当前所有可领取的总数
function calcAllCanTakeBonus()
    -- 不一定Gift商品都存在商城里
    local giftTypes = MarketM.getSuperiorAlias();

    local totalNum = 0;
    for _, value in pairs(gifts) do
        for k, v in pairs(value) do
            if canTakeGift(v.classify, v.grade) and table.indexOf(giftTypes, v.classify) ~= -1 then
                -- 计算奖励的个数
                totalNum = totalNum + 1;
            end
        end
    end

    return totalNum;
end

-- 获得该类别可领取的奖励的grade，没有可领取的返回-1
function getCanTakeGiftGrade(class)
    local grade = -1;
    local list = query(class) or {};
    for k, v in pairs(list) do
        if canTakeGift(v.classify, v.grade) then
            grade = v.grade;
            break;
        end
    end

    return grade;
end

-- 检查档位是否可以显示
function getCanShowGrade(goodsId, class)
    local maxGrade = 0;

    -- 计算当前最大可领取档位
    local list = query(class) or {};
    for k, v in pairs(list) do
        if canTakeGift(v.classify, v.grade) or beAlreadyTook(v.classify, v.grade) then
            if maxGrade < v.grade then
                maxGrade = v.grade;
            end
        end
    end

    -- 根据最大档位获得可显示的档位
    local showArgs = MarketM.query(goodsId, "show_check_args");
    if not showArgs or showArgs == "" then
        return maxGrade;
    end

    local grade = 0;
    for k, v in pairs(showArgs) do
        if maxGrade >= v[1] and v[2] > grade then
            grade = v[2];
        end
    end

    return grade;
end

-- 根据可显示的最大档位，调整列表
function ajustGradeList(goodsId, class)
    local grade = getCanShowGrade(goodsId, class);
    local list = query(class);
    local ret = {};
    for k, v in pairs(list) do
        if v.grade <= grade then
            table.insert(ret, v);
        end

    end

    return ret;
end

-- 检查击杀boss项是否可显示
function getKillBossGift()
   local gradeList = {};
   local list = query("boss") or {};
   for k, value in pairs(list) do
       local require = value.require;
       if DungeonAreaM.isAreaUnlocked(ME.user, require.dungeon_id) then
           table.insert(gradeList, value);
       end
   end

   return gradeList;
end

-- 是否显示dungeon
function isShowKillBoss()
    local t = getKillBossGift();
    return #t > 0;
end

-- 获得已领取的最大ID
function getMaxTakenGrade(class)
    local maxGrade = 0;

    -- 获得已领取最大档位
    local list = query(class) or {};
    for k, v in pairs(list) do
        if beAlreadyTook(v.classify, v.grade) then
            if maxGrade < v.grade then
                maxGrade = v.grade;
            end
        end
    end

    return maxGrade;
end

-- 获取玩家是否完成了限时礼包要求
function ifAchieveTimeLimitGift()
    local info = getLimitTimeGiftInfo();
    if info.achieve and info.achieve == 1 then
        return true;
    else
        return false;
    end
end

-- 获取玩家是否领取过了礼包
function takeTimeLimitBonusAlready()
    local info = getLimitTimeGiftInfo();
    if info.take_bonus and info.take_bonus == 1 then
        return true;
    else
        return false;
    end
end

-- 判断玩家是否可以领取礼包
function canTakeLimitBonus()
    if ifAchieveTimeLimitGift() and not takeTimeLimitBonusAlready() then
        return true;
    else
        return false;
    end
end

-- 获取玩家限时礼包数据
function getLimitTimeGiftInfo()
    local info = table.deepcopy(ME.user.dbase:query("limit_time_gift") or {});
    return info;
end

-- 是否显示限时礼包
function canShowLimitTimeGift()
    local ret = true;
    local info = getLimitTimeGiftInfo();
    if not info["gift_info"] then
        -- 没有显示礼包数据
        ret = false;
    elseif info["take_bonus"] == 1 then
        -- 已经领取过了
        ret = false;
    end
    return ret;
end

-- 显示礼包剩余时间
function getLimitGiftLeftTime()
    local serverTime = TimeM.getServerTime();
    local info = ME.user.dbase:query("limit_time_gift") or {};
    if info and info.gift_info and info.gift_info["end_time"] then
        return math.max(info.gift_info["end_time"] - serverTime, 0);
    end
    return 0;
end
